using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using Tavis.Interfaces;

namespace Tavis {
    public class SemanticsRegistry : ISemanticsRegistry, ISemanticsRepository {

		private readonly ILinkFactory _LinkFactory;
        private readonly List<MediaTypeFormatter> _Formatters = new List<MediaTypeFormatter>();
		private readonly IDictionary<Type, ILinkExtractor> _LinkExtractors = new Dictionary<Type, ILinkExtractor>();
		private readonly IDictionary<string, ILink> _Bookmarks = new Dictionary<string, ILink>();
		private readonly IDictionary<ILink, Func<HttpContent>> _PreregisteredStaticContent = new Dictionary<ILink, Func<HttpContent>>(new LinkComparer());
		
        
        public IEnumerable<MediaTypeFormatter> Formatters {
			get { return _Formatters; }
		}

        public ILinkFactory LinkFactory {
            get { return _LinkFactory; }
        }


        internal SemanticsRegistry(ILinkFactory linkFactory)
    	{
    		_LinkFactory = linkFactory;
    	}



    	public void RegisterFormatter(MediaTypeFormatter formatter)
		{
			_Formatters.Add(formatter);
        }


        public void RegisterLinkExtractor(ILinkExtractor linkExtractor)
		{
			foreach (var type in linkExtractor.SupportedTypes) {
				if (!_LinkExtractors.ContainsKey(type)) {
					_LinkExtractors.Add(type, linkExtractor);
				}
			}
        }


    	public void RegisterBookmark(string key, ILink bookmarkLink)
		{
            _Bookmarks[key] = bookmarkLink;
        }


        public void RegisterStaticContent(ILink link, Func<HttpContent> contentSource)
		{
			_PreregisteredStaticContent[link] = contentSource;
        }


    	public void RegisterLinkType<T>(string relationToMapToType) where T : ILink
    	{
			LinkFactory.RegisterLinkType<T>(relationToMapToType);
    	}


    	public ILinkExtractor GetLinkExtractor(Type type)
    	{
			if (!_LinkExtractors.ContainsKey(type)) {
				throw new LinkExtractorNotFoundException(type);
			}

			return _LinkExtractors[type];
    	}


    	public ILink GetBookmark(string key)
    	{
			return _Bookmarks.ContainsKey(key) ? _Bookmarks[key] : null;
    	}


		public HttpContent GetPreregisteredContent(ILink link)
    	{
			return _PreregisteredStaticContent.ContainsKey(link) ? _PreregisteredStaticContent[link]() : null;
    	}




		private class LinkComparer : IEqualityComparer<ILink>
		{
			public bool Equals(ILink x, ILink y)
			{
				return x.Target == y.Target && x.StateChange == y.StateChange && x.Method == y.Method;
			}


			public int GetHashCode(ILink obj)
			{
				return obj.Target.GetHashCode() ^ obj.StateChange.GetHashCode() ^ obj.Method.GetHashCode();
			}
		}
    }
}
